﻿using Autofac;
using Autofac.Extensions.DependencyInjection;
using Consul;
using DotNetCore.CAP;
using Exceptionless;
using Exceptionless.AspNetCore;
using log4net;
using log4net.Appender;
using log4net.Core;
using log4net.Layout;
using log4net.Repository.Hierarchy;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using Ongoal.Quotation.APIBase;
using Ongoal.Quotation.APIExtensions;
using Ongoal.Quotation.Cap;
using Ongoal.Quotation.Http;
using Ongoal.Quotation.Log;
using Ongoal.Quotation.Model;
using Ongoal.Quotation.Redis;
using Ongoal.Quotation.Sqlsugar;
using Ongoal.Quotation.WebApi;
using SqlSugar;
using System.Runtime.InteropServices;
using WebApiClientCore;

namespace Ongoal.Quotation
{
    public static class CommonExtensions
    {
        /// <summary>
        /// 
        /// </summary>
        public const string CorsPolicyName = "_MESAllowSpecificOrigins";
        private static IDisposable CallbackInstence { get; set; }

        private static IServiceProvider ServiceProvider { get; set; }

        private static IServiceCollection ServiceCollection { get; set; }

        public static IServiceProvider UseFramework(this IServiceCollection services, IConfiguration configuration, Action<IServiceCollection> Before, Action<ContainerBuilder> RegAction)
        {

            var serviceInfo = configuration.GetCfgValue<ServiceInfo>("BaseInfo");

            //注入日志组件
            services.AddLogging(cfg =>
            {
                //cfg.AddFilter("System", LogLevel.Warning); //过滤掉系统默认的一些日志
                //cfg.AddFilter("Microsoft", LogLevel.Warning);//过滤掉系统默认的一些日志
                cfg.AddLog4Net();
            });
            services.AddControllers(options => options.ReturnHttpNotAcceptable = true)
                .AddJsonOptions(options => options.JsonSerializerOptions.PropertyNamingPolicy = null)
                .AddNewtonsoftJson(options =>
                {
                    //设置时间格式
                    options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
                    //忽略循环应用
                    options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
                    //返回的数据是否使用驼峰
                    options.SerializerSettings.ContractResolver = new DefaultContractResolver();
                    //如果字段为null，该字段会依然返回到Json串中。如：“name”：null
                    options.SerializerSettings.NullValueHandling = NullValueHandling.Include;
                });
            //注入SqlSugarl
            services.UseSqlsugar(configuration, ServiceLifetime.Singleton);

            //注入Redis
            services.UseRedis(configuration, ServiceLifetime.Singleton);

            //注入权限
            services.UseAuthentication(configuration, ServiceLifetime.Singleton);
            services.AuthenConfig(configuration);

            //注入HTTP组件
            services.UseHttpClient(configuration, ServiceLifetime.Singleton);
            services.UseWebApiClient(configuration, ServiceLifetime.Scoped);

            //注入分布式事务
            services.UseCap(configuration);

            //注入分布式事务
            var exceptionlessInfo = configuration.GetCfgValue<ExceptionlessConfigModel>("Exceptionless");

            if (exceptionlessInfo != null && exceptionlessInfo.Enable)
            {
                services.AddExceptionless(configuration);
            }
            services.AddSingleton<IDistributedLog, DistributedLog>();


            services.AddControllers();
            // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
            services.AddEndpointsApiExplorer();
            services.AddSwaggerGen(config =>
            {
                var xmlArray = Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "*.xml");
                //var xmlPath = Path.Combine(basePath, "Ongoal.TemplateAPI.xml");//接口action显示注释
                foreach (var xml in xmlArray)
                {
                    config.IncludeXmlComments(xml);
                }
            });

            //注册上下文服务
            services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();

            //if (configuration["ASPNETCORE_ENVIRONMENT"] == "Development")
            //{
            //开发环境下
            //统一加上服务名称的前缀
            // 2025年4月9日14:22:16 本次为单服务开发，取消前缀
            //services.AddMvc(options =>
            //{
            //    options.RespectBrowserAcceptHeader = true;
            //    options.UseCentralRoutePrefix(new Microsoft.AspNetCore.Mvc.RouteAttribute(serviceInfo!.ApiName!));//设置全局路由前缀
            //});
            //}


            if (Before != null)
                Before(services);


            var builder = new ContainerBuilder();
            builder.Populate(services);

            if (RegAction != null)
                RegAction(builder);

            var Container = builder.Build();
            ServiceProvider = new AutofacServiceProvider(Container);
            ServiceProviderContext.ServiceProvider = ServiceProvider;
            ServiceProviderContext.HttpContextAccessor = ServiceProvider.GetService(typeof(IHttpContextAccessor)) as IHttpContextAccessor;

            return ServiceProvider;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="configuration"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static T? GetCfgValue<T>(this IConfiguration configuration, string key)
        {
            var tempstr = configuration[key];
            T? cfgs = default(T);
            if (!string.IsNullOrEmpty(tempstr))
                cfgs = JsonConvert.DeserializeObject<T>(tempstr);
            else
                cfgs = configuration.GetSection(key).Get<T>();
            return cfgs;
        }

        #region Log4Net注入
        /// <summary>
        /// 使用Log4Net
        /// </summary>
        /// <param name="services"></param>
        /// <param name="configuration"></param>
        /// <returns></returns>
        public static IServiceCollection UseLog4Net(this IServiceCollection services, IConfiguration configuration, ServiceLifetime lifetime = ServiceLifetime.Singleton)
        {
            Hierarchy hierarchy = (Hierarchy)LogManager.GetRepository();

            PatternLayout patternLayout = new PatternLayout();
            patternLayout.ConversionPattern = "%date [%thread] %-5level %logger - %message%newline";
            patternLayout.ActivateOptions();

            RollingFileAppender roller = new RollingFileAppender();
            roller.AppendToFile = false;
            roller.File = @"Logs\EventLog.txt";
            roller.Layout = patternLayout;
            roller.MaxSizeRollBackups = 5;
            roller.MaximumFileSize = "1GB";
            roller.RollingStyle = RollingFileAppender.RollingMode.Size;
            roller.StaticLogFileName = true;
            roller.ActivateOptions();
            hierarchy.Root.AddAppender(roller);

            MemoryAppender memory = new MemoryAppender();
            memory.ActivateOptions();
            hierarchy.Root.AddAppender(memory);

            hierarchy.Root.Level = Level.Info;
            hierarchy.Configured = true;

            return services;
        }
        #endregion

        #region 注入SqlSugarl
        /// <summary>
        /// 注入SqlSugar
        /// </summary>
        /// <typeparam name="TSugarContext"></typeparam>
        /// <param name="serviceCollection"></param>
        /// <param name="configuration"></param>
        /// <param name="lifetime"></param>
        /// <returns></returns>
        public static IServiceCollection UseSqlsugar(this IServiceCollection serviceCollection, IConfiguration configuration, ServiceLifetime lifetime = ServiceLifetime.Singleton)
        {
            serviceCollection.AddMemoryCache().AddLogging();
            serviceCollection.RemoveAll(typeof(List<DbConfig>));
            serviceCollection.TryAdd(new ServiceDescriptor(typeof(List<DbConfig>), p => ConnectionConfigFactory(p, configuration), lifetime));
            serviceCollection.Add(new ServiceDescriptor(typeof(List<DbConfig>), p => ConnectionConfigFactory(p, configuration), lifetime));
            serviceCollection.TryAdd(new ServiceDescriptor(typeof(IDbFactory), typeof(DbFactory), lifetime));
            return serviceCollection;
        }
        private static List<DbConfig> ConnectionConfigFactory(IServiceProvider applicationServiceProvider, IConfiguration config)
        {
            var dbConfigstr = config["DBConfig"];
            List<DbConfig>? cfgs = null;
            if (!string.IsNullOrEmpty(dbConfigstr))
                cfgs = JsonConvert.DeserializeObject<List<DbConfig>>(dbConfigstr);
            else
                cfgs = config.GetSection("DBConfig").Get<List<DbConfig>>();
            if (cfgs == null || cfgs.Count == 0)
                throw new Exception("数据库配置错误，请检查数据库配置");
            return cfgs;

        }
        #endregion

        #region 使用Redis
        /// <summary>
        /// 使用Redis
        /// </summary>
        /// <param name="services"></param>
        /// <param name="configuration"></param>
        /// <returns></returns>
        public static IServiceCollection UseRedis(this IServiceCollection services, IConfiguration configuration, ServiceLifetime lifetime = ServiceLifetime.Singleton)
        {
            //获取redis配置
            var cfgs = configuration.GetCfgValue<List<RedisConfig>>("Redis");
            services.AddMemoryCache().AddLogging();
            services.RemoveAll(typeof(List<RedisConfig>));
            services.TryAdd(new ServiceDescriptor(typeof(List<RedisConfig>), p => { return cfgs; }, lifetime));
            services.Add(new ServiceDescriptor(typeof(List<RedisConfig>), p => { return cfgs; }, lifetime));
            services.TryAdd(new ServiceDescriptor(typeof(IRedisProvider), typeof(RedisProvider), lifetime));
            //services.TryAdd(new ServiceDescriptor(typeof(IDataCacheService), typeof(DataCacheService), lifetime));
            return services;
        }
        #endregion

        #region 注册权限组件
        public static IServiceCollection UseAuthentication(this IServiceCollection serviceCollection, IConfiguration configuration, ServiceLifetime lifetime = ServiceLifetime.Singleton)
        {
            var cfgs = new JwtConfig();
            serviceCollection.AddMemoryCache().AddLogging();
            serviceCollection.TryAdd(new ServiceDescriptor(typeof(JwtConfig), p => { return cfgs; }, lifetime));
            serviceCollection.Add(new ServiceDescriptor(typeof(JwtConfig), p => { return cfgs; }, lifetime));
            serviceCollection.TryAdd(new ServiceDescriptor(typeof(IAuthentication), typeof(AuthenticationProvider), lifetime));
            return serviceCollection;
        }

        private static IServiceCollection AuthenConfig(this IServiceCollection services, IConfiguration configuration)
        {
            var authSetting = configuration.GetCfgValue<AuthSetting>("AuthSetting");
            var serviceInfo = configuration.GetCfgValue<ServiceInfo>("BaseInfo");
            services.AddAuthentication("Bearer")
                  .AddIdentityServerAuthentication(options =>
                  {

                      options.Authority = authSetting!.Server;
                      options.RequireHttpsMetadata = false;
                      options.ApiName = serviceInfo!.ApiName;
                  }).AddCookie();
            services.AddCors(options =>
            {
                options.AddPolicy(name: CommonExtensions.CorsPolicyName,
                                  builder =>
                                  {
                                      builder.WithOrigins(authSetting!.Cors.ToArray())
                                        .AllowAnyHeader()
                                        .AllowAnyMethod();
                                  });
            });
            services.AddSingleton<IAuthorizationHandler, APIAuthorizationHandler>();
            return services;
        }
        #endregion


        #region 扩展路由
        /// <summary>
        /// 扩展全局路由
        /// </summary>
        /// <param name="opts"></param>
        /// <param name="routeAttribute"></param>
        public static void UseCentralRoutePrefix(this MvcOptions opts, IRouteTemplateProvider routeAttribute)
        {
            // 添加我们自定义 实现IApplicationModelConvention的RouteConvention
            opts.Conventions.Insert(0, new RouteConvention(routeAttribute));
        }
        #endregion

        #region Http组件注入

        /// <summary>
        /// Http组件
        /// </summary>
        /// <param name="services"></param>
        /// <param name="configuration"></param>
        /// <returns></returns>
        public static IServiceCollection UseHttpClient(this IServiceCollection services, IConfiguration configuration, ServiceLifetime lifetime = ServiceLifetime.Singleton)
        {
            //获取redis配置
            services.TryAdd(new ServiceDescriptor(typeof(IMircoServiceClient), typeof(MircoServiceClient), lifetime));
            return services;
        }

        /// <summary>
        /// Http组件
        /// </summary>
        /// <param name="services"></param>
        /// <param name="configuration"></param>
        /// <returns></returns>
        public static IServiceCollection UseWebApiClient(this IServiceCollection services, IConfiguration configuration, ServiceLifetime lifetime = ServiceLifetime.Singleton)
        {
            services.AddWebApiClient().ConfigureHttpApi((options, serviceProvider) =>
            {
                options.GlobalFilters.Add(new InternalApiFilterAttribute(configuration));
            });
            services.AddHttpApi<IWebApiRequest>();
            services.AddHttpApi<IExternalWebApiRequest>();
            return services;
        }

        #endregion

        #region 注入分布式事务

        private static RabbitMQConfigModel? GetRabbitMQConfig(IConfiguration config)
        {
            var mqConfigstr = config["RabbitMQ"];
            RabbitMQConfigModel? cfg = null;
            try
            {
                if (!string.IsNullOrEmpty(mqConfigstr))
                    cfg = JsonConvert.DeserializeObject<RabbitMQConfigModel>(mqConfigstr);
                else
                    cfg = config.GetSection("RabbitMQ").Get<RabbitMQConfigModel>();
            }
            catch
            {

            }

            return cfg;

        }
        public static CapConfigModel? GetCapConfig(IConfiguration config)
        {
            var dbCapConfigStr = config["CapConfig"];
            CapConfigModel? cfg = null;
            try
            {
                if (!string.IsNullOrEmpty(dbCapConfigStr))
                    cfg = JsonConvert.DeserializeObject<CapConfigModel>(dbCapConfigStr);
                else
                    cfg = config.GetSection("CapConfig").Get<CapConfigModel>();
            }
            catch
            {
                cfg = new CapConfigModel() { Enable = false };
            }

            return cfg;

        }

        /// <summary>
        /// 注入分布式事务
        /// </summary>
        /// <param name="services"></param>
        /// <param name="configuration"></param>
        /// <returns></returns>
        public static IServiceCollection UseCap(this IServiceCollection services, IConfiguration configuration)
        {

            CapConfigModel capConfig = GetCapConfig(configuration);
            if (capConfig == null || capConfig.Enable != true)
            {
                services.TryAddSingleton<ICapPublisher, MessageNullPublisher>();
                services.TryAddSingleton<IMessagePublisher, MessagePublisher>();
                return services;
            }
            List<DbConfig> dbConfigs = ConnectionConfigFactory(null, configuration);
            if (dbConfigs == null || dbConfigs.Count == 0)
            {
                throw new Exception($"CAP数据库配置错误，请检查数据库配置");
            }
            string dbConnectionStr = null;
            if (!String.IsNullOrWhiteSpace(capConfig.CapDBName))
            {
                var db = dbConfigs.FirstOrDefault(m => m.Name == capConfig.CapDBName);
                if (db == null)
                {
                    throw new Exception($"CAP数据库[{capConfig.CapDBName}]配置错误，请检查数据库配置");
                }
                dbConnectionStr = db.ConnectionStr;
            }
            else
            {
                dbConnectionStr = dbConfigs.First().ConnectionStr!;
            }


            RabbitMQConfigModel? rabbitMQConfig = GetRabbitMQConfig(configuration);
            if (rabbitMQConfig == null)
            {
                throw new Exception($"RabbitMQ配置错误，请检查相关配置");
            }
            services.AddCap(x =>
            {
                //配置Cap的本地消息记录库，用于服务端保存Published消息记录表；客户端保存Received消息记录表

                // 此方法默认使用的数据库Schema为Cap；2，要求最低sql server2012(因为使用了Dashboard的sql查询语句使用了Format新函数)
                //x.UseSqlServer("Integrated Security=False;server=服务器;database=cap;User ID=sa;Password=密码;Connect Timeout=30"); 

                // 配置Cap的本地消息记录库，用于服务端保存Published消息记录表；客户端保存Received消息记录表

                x.UseMySql(dbConnectionStr);

                //使用RabbitMQ作为底层之间的消息发送
                x.UseRabbitMQ(mq =>
                {
                    mq.HostName = rabbitMQConfig.HostName; //RabitMq服务器地址，依实际情况修改此地址
                    mq.Port = rabbitMQConfig.Port!.Value;
                    mq.UserName = rabbitMQConfig.UserName;  //RabbitMq账号
                    mq.Password = rabbitMQConfig.Password;  //RabbitMq密码
                    mq.VirtualHost = rabbitMQConfig.VirtualHost;

                    //mq.ExchangeName = rabbitMQConfig.ExchangeName;
                });

                //使用Dashboard，这是一个Cap的可视化管理界面；默认地址:http://localhost:端口/cap
                x.UseDashboard();


                //默认分组名，此值不配置时，默认值为当前程序集的名称
                //x.DefaultGroup = "Ongoal";
                //失败后的重试次数，默认50次；在FailedRetryInterval默认60秒的情况下，即默认重试50*60秒(50分钟)之后放弃失败重试
                x.FailedRetryCount = 10;

                //失败后的重拾间隔，默认60秒
                x.FailedRetryInterval = 100;

                //设置成功信息的删除时间默认24*3600秒
                x.SucceedMessageExpiredAfter = 24 * 60 * 60;
                //设置失败信息的删除时间默认24*3600秒
                x.FailedMessageExpiredAfter = 24 * 3600 * 365 * 1;
            }).AddSubscribeFilter<MessageSubscribeFilter>(); ;
            services.TryAddSingleton<IMessagePublisher, MessagePublisher>();
            services.TryAddSingleton<MessageDefaultCallbackExecutor>();
            return services;
        }
        #endregion

        #region 注入注册中心
        /// <summary>
        /// 注入Consul注册中心
        /// </summary>
        /// <param name="app"></param>
        /// <param name="configuration"></param>
        /// <param name="lifetime"></param>
        /// <returns></returns>
        public static IApplicationBuilder UseRegisterConsul(this IApplicationBuilder app, IConfiguration configuration, IHostApplicationLifetime lifetime)
        {
            ServiceEntity serviceEntity = null;
            var serviceInfo = configuration.GetCfgValue<ServiceInfo>("BaseInfo");
            //获取本地服务客户端注册配置
            string serviceDiscoveryClientKey = "ServiceDiscoveryClient";
            ServiceDiscoveryClient serviceDiscoveryClient = null;
            if (configuration.GetSection(serviceDiscoveryClientKey) != null)
                serviceDiscoveryClient = configuration.GetSection(serviceDiscoveryClientKey).Get<ServiceDiscoveryClient>();

            ServiceProviderContext.ServiceDiscoveryClient = serviceDiscoveryClient;
            if (serviceDiscoveryClient == null || serviceDiscoveryClient.RegistyType != "Consul")
            {
                return app;
            }

            //获取配置中心服务发现配置
            string registryInfoKey = "Consul";
            string registryInfo = configuration[registryInfoKey];
            if (!string.IsNullOrWhiteSpace(registryInfo))
                serviceEntity = JsonConvert.DeserializeObject<ServiceEntity>(registryInfo);
            else
                serviceEntity = configuration.GetSection(registryInfoKey).Get<ServiceEntity>();


            if (serviceEntity != null)
            {
                //ServiceProviderContext.RregisterCenter = new KeyValueModel() { Key = "Consul", value = $"http://{serviceEntity.ConsulIP}:{serviceEntity.ConsulPort}/" };
                //获取当前地址注册到注册中心
                //string urls = configuration["urls"];
                string ip = GetCurIpAddress();
                Console.WriteLine($"注册IP地址:[{ip}]");

                try
                {
                    if (!String.IsNullOrWhiteSpace(serviceDiscoveryClient.ServiceClientHost))
                    {
                        serviceDiscoveryClient.ServiceClientHost = serviceDiscoveryClient.ServiceClientHost.Replace("*", ip);
                        Uri host = new Uri(serviceDiscoveryClient.ServiceClientHost);
                        var healthPath = serviceEntity.CheckPath;
                        if (String.IsNullOrWhiteSpace(healthPath))
                        {
                            healthPath = $"{serviceDiscoveryClient.ServiceClientHost}/{ApplicationExtensions.HealthPath}".Replace("//", "/").Replace(":/", "://");
                        }
                        else
                        {
                            string lowerHealthPath = healthPath.ToLower();
                            if (lowerHealthPath.StartsWith("http://") || lowerHealthPath.StartsWith("https://"))
                            {

                            }
                            else
                            {
                                healthPath = $"{serviceDiscoveryClient.ServiceClientHost}/{serviceEntity.CheckPath}".Replace("//", "/").Replace(":/", "://");
                            }
                        }
                        var consulClient = new ConsulClient(x => x.Address = new Uri($"http://{serviceEntity.ConsulIP}:{serviceEntity.ConsulPort}"));//请求注册的 Consul 地址
                        var httpCheck = new AgentServiceCheck()
                        {
                            DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(1),//服务启动多久后注册
                            Interval = TimeSpan.FromSeconds(serviceEntity.CheckTime),//健康检查时间间隔，或者称为心跳间隔
                            HTTP = healthPath,//健康检查地址
                            Timeout = TimeSpan.FromSeconds(serviceEntity.CheckTimeOut)
                        };
                        List<string> tagList = new List<string>() { $"urlprefix-/{serviceInfo.ApiName}" };
                        if (serviceDiscoveryClient.Tags != null && serviceDiscoveryClient.Tags.Count > 0)
                        {
                            tagList.AddRange(serviceDiscoveryClient.Tags);
                        }
                        var registration = new AgentServiceRegistration()
                        {
                            Checks = new[] { httpCheck },
                            ID = ServiceHelper.GetServiceId(),
                            Name = serviceInfo.ApiName,
                            Address = host.Host,
                            Port = host.Port,
                            Tags = tagList.ToArray()
                        };
                        Console.WriteLine("开始反注册重复注册服务");
                        ConuslServiceDeregister(registration, consulClient, true);

                        consulClient.Agent.ServiceRegister(registration).Wait();//服务启动时注册，内部实现其实就是使用 Consul API 进行注册（HttpClient发起）
                        lifetime.ApplicationStopping.Register(() =>
                        {
                            //consulClient.Agent.ServiceDeregister(registration.ID).Wait();//服务停止时取消注册
                            Console.WriteLine("停止程序开始反注册重复注册服务");
                            ConuslServiceDeregister(registration, consulClient, false);
                        });
                        return app;
                    }
                }
                catch (Exception ex)
                {
                    throw new Exception($"注册服务器{serviceEntity.ConsulIP}:{serviceEntity.ConsulPort}失败：", ex);
                }
            }
            return app;
        }

        private static void ConuslServiceDeregister(AgentServiceRegistration registration, ConsulClient consulClient, bool onlyByServiceId = true)
        {
            var queryResult = consulClient.Health.Service(registration.Name, null, true).Result;
            foreach (var serviceEntry in queryResult.Response)
            {
                if (registration.ID == serviceEntry.Service.ID || (!onlyByServiceId && serviceEntry.Service.Address == registration.Address && serviceEntry.Service.Port == registration.Port))
                {
                    consulClient.Agent.ServiceDeregister(serviceEntry.Service.ID).Wait();
                }
            }
        }

        /// <summary>
        /// 获取系统IP
        /// </summary>
        /// <returns></returns>
        private static string GetCurIpAddress()
        {
            Console.WriteLine($"注册IP地址");
            string? ip = Environment.GetEnvironmentVariable("MY_POD_IP");
            if (!string.IsNullOrEmpty(ip))
                return ip;

            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                Console.WriteLine($"获取Windows宿主机器IP信息:{ip}");
                ip = System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces()
                   .Select(p => p.GetIPProperties())
                   .SelectMany(p => p.UnicastAddresses)
                   .Where(p => p.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork && !System.Net.IPAddress.IsLoopback(p.Address)).Where(x => x.PrefixOrigin == System.Net.NetworkInformation.PrefixOrigin.Dhcp)
                   .FirstOrDefault()?.Address.ToString();
                if (string.IsNullOrEmpty(ip))
                {
                    ip = System.Net.Dns.GetHostEntry(System.Net.Dns.GetHostName()).AddressList.FirstOrDefault(address => address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)?.ToString();

                }
                return ip;
            }
            else
            {
                return GetLinuxOsIp();
            }
        }
        /// <summary>
        /// 获取Linux系统IP
        /// </summary>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public static string GetLinuxOsIp()
        {
            Console.WriteLine($"获取Linux容器宿主机器信息");
            string? ip = Environment.GetEnvironmentVariable("MY_POD_IP");
            if (!string.IsNullOrEmpty(ip))
                return ip;
            var files = "/etc/bindipcfg/bindip.cfg";
            string line = string.Empty;
            if (System.IO.File.Exists(files))
            {
                FileStream fileStream = new FileStream(files, FileMode.Open);
                using (StreamReader reader = new StreamReader(fileStream))
                {
                    try
                    {
                        line = reader.ReadToEnd();

                        if (string.IsNullOrEmpty(line))
                        {
                            Console.WriteLine($"部署前请设置主机{files}文件");
                            throw new Exception($"部署前请设置主机{files}文件");
                        }
                        else
                        {
                            var hostinfos = line.Split(new char[] { '=' });
                            return hostinfos[1].Replace("\n", "").Replace(" ", "").Replace("\t", "").Replace("\r", "");
                        }
                    }
                    catch (Exception ex)
                    {

                        throw ex;
                    }
                    finally
                    {
                        reader.Close();
                        reader.Dispose();
                    }

                }
            }
            else
            {
                Console.WriteLine($"找不到{files}文件");
                throw new Exception($"找不到{files}文件");
            }
        }
        #endregion

        #region 注入分布式日志
        /// <summary>
        /// 注入Consul注册中心
        /// </summary>
        /// <param name="app"></param>
        /// <param name="configuration"></param>
        /// <param name="lifetime"></param>
        /// <returns></returns>
        public static IApplicationBuilder UseExceptionless(this IApplicationBuilder app, IConfiguration configuration, IHostApplicationLifetime lifetime)
        {
            var exceptionlessInfo = configuration.GetCfgValue<ExceptionlessConfigModel>("Exceptionless");

            if (exceptionlessInfo == null || !exceptionlessInfo.Enable)
            {
                ExceptionlessClient.Default.Configuration.Enabled = false;
                ExceptionlessClient.Default.Configuration.ApiKey = "NoApiKey";
                ExceptionlessClient.Default.Configuration.ServerUrl = "";

                return app;
            }
            ExceptionlessClient.Default.Configuration.ApiKey = exceptionlessInfo.ApiKey;
            ExceptionlessClient.Default.Configuration.ServerUrl = exceptionlessInfo.ServerUrl;
            ExceptionlessClient.Default.Configuration.IncludePostData = true;
            ExceptionlessClient.Default.Configuration.IncludeQueryString = true;
            ExceptionlessClient.Default.Configuration.IncludeIpAddress = true;

            ExceptionlessClient.Default.SubmittingEvent += OnSubmittingEvent;

            app.UseExceptionless();
            return app;
        }
        private static void OnSubmittingEvent(object sender, EventSubmittingEventArgs e)
        {
            //// 仅处理未被处理过的异常
            //if (!e.IsUnhandledError)
            //    return;

            //// 忽略404事件
            //if (e.Event.IsNotFound())
            //{
            //    e.Cancel = true;
            //    return;
            //}

            // 获取error对象
            var error = e.Event.GetError();
            //if (error == null)
            //    return;

            // 忽略 401 或 `HttpRequestValidationException`异常
            if (error != null && error.Code == "401")//|| error.Type == "System.Web.HttpRequestValidationException"
            {
                e.Cancel = true;
                return;
            }

            //// 忽略不是指定命名空间代码抛出的异常
            //var handledNamespaces = new List<string> { "Exceptionless" };
            //if (!error.StackTrace.Select(s => s.DeclaringNamespace).Distinct().Any(ns => handledNamespaces.Any(ns.Contains)))
            //{
            //    e.Cancel = true;
            //    return;
            //}

            //添加服务Id
            if (e.Event.Data != null && e.Event.Data.ContainsKey("@environment"))
            {
                var environment = e.Event.Data["@environment"] as Exceptionless.Models.Data.EnvironmentInfo;
                if (!environment.Data.ContainsKey("InstallId"))
                    environment.Data.Add("InstallId", ServiceHelper.GetServiceId());
            }
            UserInfo user = null;
            var httpContext = ServiceProviderContext.HttpContextAccessor?.HttpContext;
            if (httpContext != null)
            {
                var allClaims = from c in httpContext.Request.HttpContext.User.Claims select new { c.Type, c.Value };
                if (allClaims != null)
                {
                    var loguser = allClaims.FirstOrDefault(x => x.Type == "loginuser");
                    if (loguser != null)
                    {
                        string loginfo = Des.Decrypt(loguser.Value, Des.DefaultKEY);
                        user = JsonConvert.DeserializeObject<UserInfo>(loginfo);
                    }
                }
                if (user != null)
                {
                    string userCode = String.IsNullOrWhiteSpace(user.UserName) ? user.UserCode : user.UserName;
                    e.Event.SetUserIdentity(new Exceptionless.Models.Data.UserInfo(user.UserID.ToString(), userCode));
                }
            }

            if (String.IsNullOrWhiteSpace(e.Event.Source))
            {
                e.Event.Source = AppDomain.CurrentDomain.FriendlyName;
            }
            if (e.Event.Tags == null || (!e.Event.Tags.Contains(DistributedLogTagConstant.InternalInterface) && !e.Event.Tags.Contains(DistributedLogTagConstant.ExternaInterface)))
            {
                e.Event.AddTags(DistributedLogTagConstant.InternalInterface);
            }
            if (e.Event.Tags.Contains(DistributedLogTagConstant.ExternaInterface))
            {
                if (e.PluginContextData.ContainsKey("WebApiContent"))
                {
                    var webApiContent = e.PluginContextData["WebApiContent"];
                    if (webApiContent is ApiResponseContext)
                    {
                        var item = webApiContent as ApiResponseContext;
                        var requestInfo = e.Event.GetRequestInfo();
                        if (requestInfo != null)
                        {
                            requestInfo = RequestInfoCollector.CollectByWebApi(item, requestInfo, e.Client.Configuration);
                            e.Event.AddRequestInfo(requestInfo);
                        }
                    }
                    e.PluginContextData.Remove("WebApiContent");
                }
            }


        }
        #endregion
    }
}
